package cn.edu.nju.ws.sview.rdf;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;

import org.apache.log4j.Logger;

import cn.edu.nju.ws.sview.database.DBConnectionFactory;
import cn.edu.nju.ws.sview.reasoning.Repository;

/**
 * �й�RDF��ݲ����Ĺ�����
 * @author Gong Saisai
 *
 */
public class RDFFactory {
    private Logger logger  = Logger.getLogger(RDFFactory.class.getName()) ;
	private RDFFactory(){
		
	}
	
	private static RDFFactory INSTANCE = null;
	/**
	 * 
	 * @return �ù�����ĵ���
	 */
	public static synchronized RDFFactory getInstance() {
		if (INSTANCE == null) {
			INSTANCE = new RDFFactory();
		}
		return INSTANCE;
	}
	
	/**
	 * ���Ҫ�����ݿ��ȡ��Ԫ��
	 * @param subject ����ΪNULLʱ��ʾ����Ҫ��
	 * @param property ν��ΪNULLʱ��ʾ����Ҫ��
	 * @param object ����ΪNULLʱ��ʾ����Ҫ��
	 * @param document �ĵ�ΪNULLʱ��ʾ����Ҫ��
	 * @return ��Ԫ���б�
	 */
	public ArrayList<RDFTriple> query(
			Resource subject, Resource property, Resource object, RDFDocument document){
		ArrayList<RDFTriple> triples = new ArrayList<RDFTriple>();
		StringBuffer where = new StringBuffer("where ");
		
		// Generate where of SQL
		if ( subject != null ) {
			String s = Repository.getInstance().getIDByResource(subject);
			where.append("s = '" + s + "' and ");
		}
		if ( property != null ) {
			String p = Repository.getInstance().getIDByResource(property);
			where.append("p = '" + p + "' and ");
		}
		if ( object != null ) {
			String o = Repository.getInstance().getIDByResource(object);
			where.append("o = '" + o + "' and ");
			
			if ( object instanceof PlainLiteral ) {
				String lang = ((PlainLiteral) object).getLanguageTag();
				where.append("lang = '" + lang + "' and ");
				
			} else if ( object instanceof TypedLiteral ) {
				String typeIdString = Repository.getInstance().getIDByResource(
									((TypedLiteral) object).getDatatypeURI());
				// typeIdString = uxxxx
				where.append("datatypeId = " + 
						typeIdString.substring(1) + " and ");
			}
		}
		if ( document != null ) {
			String d = Repository.getInstance().getIDByResource(document.getURI());
			int docId = Integer.parseInt(d.substring(1)); // d = uxxxx
			where.append("doc_id = " + docId + " and ");
		}

		if ( where.toString().equals("where ") ) { 
			/* all null, so no 'where' in SQL
			 * where must toString first because
			 * StringBuffer haven't override 'equals'
			 */
			where.delete(0, where.length());
		} else {
			// delete the last ' and '
			where.delete(where.lastIndexOf(" and "), where.length());
		}
		
		Resource subjectX = subject;
		Resource propertyX = property;
		Resource objectX = object;
		RDFDocument documentX = document;
		// find in DATABASE
		try {
			
			Connection con = DBConnectionFactory.getConnection();
			Statement stmt = con.createStatement();
			ResultSet rs = stmt.executeQuery(
						"select * " +
						"from quadruple " +
						where.toString());
			while ( rs.next() ) {
				
				if ( subject == null ) {
					String s = rs.getString("s");
					subjectX = Repository.getInstance().getResourceById(s, null, "");
				}
				if ( property == null ) {
					String p = rs.getString("p");
					propertyX = Repository.getInstance().getResourceById(p, null, null);
				}
				if ( object == null ) {
					String o = rs.getString("o");
					String datatypeidString = rs.getString("datatypeid");
					String lang = rs.getString("lang");
					objectX = Repository.getInstance().getResourceById(o, datatypeidString, lang);
				}
				if ( document == null ) {
					String d = rs.getString("doc_id");
					documentX = ResourceFactory.getInstance().createRDFDocument(
									((URIResource) Repository.getInstance().
									getResourceById("u" + d, null, null)).
									getURI());
				}
				
				RDFTriple triple = new RDFTriple(
						subjectX, propertyX, objectX, documentX);
				
				triples.add(triple);
			}
			stmt.close();
			con.close();
			
		} catch (SQLException e) {
			e.printStackTrace();
		}
		
		return triples;
	}
	
	/**
	 * ����һ���ĵ���Ȩ���ĵ���ַ
	 * @param docURI
	 * @return Ȩ���ĵ���ַ ������ʱΪNULL
	 */
	public URIResource getDereferenceDocument(String docURI) {
		URIResource resource = null;
		String str = null;
		Connection con = DBConnectionFactory.getConnection();
		try {
			PreparedStatement ps = con.prepareStatement("select doc_id from uri,dereference_info where uri=? and id=uri_id ") ;
			PreparedStatement urips = con.prepareStatement("select uri from uri where id=?") ;
			ps.setString(1, docURI);
			int id = 0;
			ResultSet rs =ps.executeQuery();
			if(rs.next()){
				id = rs.getInt("doc_id");
			}
			rs.close();
			ps.close();
			urips.setInt(1, id) ;
			ResultSet urirs = urips.executeQuery();
			if(urirs.next()){
				str = urirs.getString("uri") ;
			}
			urirs.close();
			con.close();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		if(str!=null)
			resource = ResourceFactory.getInstance().createURIResource(str) ;
		return resource;
	}
}
